#include <iostream>
#include <vector>
using namespace std;

class segment_tree {
	long LOWEST = INT64_MIN;

	vector<int> &arr;
	vector<long> sum;
	vector<long> imax;
	vector<long> mcnt;
	vector<long> isem;
	vector<long> hismax;

	vector<long> maxaddtop;
	vector<long> othaddtop;

	vector<long> maxadd;
	vector<long> othadd;

	void lazy(int i, int n, long madd, long oadd, long maxup, long othup)
	{
		hismax[i] = max(hismax[i], imax[i] + maxup);
		maxaddtop[i] = max(maxaddtop[i], maxadd[i] + maxup);
		othaddtop[i] = max(othaddtop[i], othadd[i] + othup);

		sum[i] += (n - mcnt[i]) * oadd + madd * mcnt[i];
		imax[i] += madd;
		isem[i] += isem[i] == LOWEST ? 0 : oadd;
		hismax[i] = max(hismax[i], imax[i]);

		maxadd[i] += madd;
		othadd[i] += oadd;
		maxaddtop[i] = max(maxaddtop[i], madd);
		othaddtop[i] = max(othaddtop[i], oadd);
	}

	void up(int i)
	{
		int l = i << 1;
		int r = i << 1 | 1;
		sum[i] = sum[l] + sum[r];
		imax[i] = max(imax[l], imax[r]);
		hismax[i] = max(hismax[l], hismax[r]);

		if (imax[l] == imax[r]) {
			mcnt[i] = mcnt[l] + mcnt[r];
			isem[i] = max(isem[l], isem[r]);
		} else if (imax[l] > imax[r]) {
			mcnt[i] = mcnt[l];
			isem[i] = max(isem[l], imax[r]);
		} else {
			mcnt[i] = mcnt[r];
			isem[i] = max(isem[r], imax[l]);
		}
	}

	void down(int i, int ln, int rn)
	{
		int l = i << 1;
		int r = i << 1 | 1;

		long tmp = max(imax[l], imax[r]);
		if (tmp == imax[l]) {
			lazy(i << 1, ln, maxadd[i], othadd[i], maxaddtop[i], othaddtop[i]);
		} else {
			lazy(i << 1, ln, othadd[i], othadd[i], othaddtop[i], othaddtop[i]);
		}

		if (tmp == imax[r]) {
			lazy(i << 1 | 1, rn, maxadd[i], othadd[i], maxaddtop[i], othaddtop[i]);
		} else {
			lazy(i << 1 | 1, rn, othadd[i], othadd[i], othaddtop[i], othaddtop[i]);
		}

		maxadd[i] = othadd[i] = maxaddtop[i] = othaddtop[i] = 0;
	}

    public:
	segment_tree(int n, vector<int> &arr)
		: arr(arr), sum(n << 2, 0), imax(n << 2, 0), isem(n << 2, 0), mcnt(n << 2, 0), hismax(n << 2, 0), maxadd(n << 2, 0), othadd(n << 2, 0), maxaddtop(n << 2, 0), othaddtop(n << 2, 0)
	{
		build(1, n, 1);
	}

	void build(int l, int r, int i)
	{
		if (l == r) {
			sum[i] = imax[i] = hismax[i] = arr[l];
			mcnt[i] = 1;
			isem[i] = LOWEST;
		} else {
			int mid = (l + r) >> 1;
			build(l, mid, i << 1);
			build(mid + 1, r, i << 1 | 1);
			up(i);
		}
		maxadd[i] = othadd[i] = maxaddtop[i] = othaddtop[i] = 0;
	}

	void set_min(int jobl, int jobr, long v, int l, int r, int i)
	{
		if (imax[i] <= v) {
			return;
		}
		if (jobl <= l && r <= jobr && isem[i] < v) {
			lazy(i, r - l + 1, v - imax[i], 0, 0, 0);
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			if (jobl <= mid) {
				set_min(jobl, jobr, v, l, mid, i << 1);
			}
			if (mid < jobr) {
				set_min(jobl, jobr, v, mid + 1, r, i << 1 | 1);
			}
			up(i);
		}
	}

	void update(int jobl, int jobr, long v, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			lazy(i, r - l + 1, v, v, v, v);
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			if (jobl <= mid) {
				update(jobl, jobr, v, l, mid, i << 1);
			}
			if (mid < jobr) {
				update(jobl, jobr, v, mid + 1, r, i << 1 | 1);
			}
			up(i);
		}
	}

	long query_max(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			return imax[i];
		}
		int mid = (l + r) >> 1;
		down(i, mid - l + 1, r - mid);

		long ans = -1;
		if (jobl <= mid) {
			ans = max(ans, query_max(jobl, jobr, l, mid, i << 1));
		}
		if (mid < jobr) {
			ans = max(ans, query_max(jobl, jobr, mid + 1, r, i << 1 | 1));
		}
		return ans;
	}

	long query_sum(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			return sum[i];
		}
		int mid = (l + r) >> 1;
		down(i, mid - l + 1, r - mid);

		long ans = 0;
		if (jobl <= mid) {
			ans += query_sum(jobl, jobr, l, mid, i << 1);
		}
		if (mid < jobr) {
			ans += query_sum(jobl, jobr, mid + 1, r, i << 1 | 1);
		}
		return ans;
	}

	long query_hismax(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			return hismax[i];
		}
		int mid = (l + r) >> 1;
		down(i, mid - l + 1, r - mid);

		long ans = INT64_MIN;
		if (jobl <= mid) {
			ans = max(ans, query_hismax(jobl, jobr, l, mid, i << 1));
		}
		if (mid < jobr) {
			ans = max(ans, query_hismax(jobl, jobr, mid + 1, r, i << 1 | 1));
		}
                return ans;
	}
};

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, m;
	cin >> n >> m;
	vector<int> arr(n + 1, 0);
	for (int i = 1; i <= n; i++) {
		cin >> arr[i];
	}

	segment_tree sgt(n, arr);
        long v = 0;
	for (int i = 0, op, l, r; i < m; i++) {
		cin >> op >> l >> r;
		switch (op) {
		case 1:
                        cin >> v;
                        sgt.update(l, r, v, 1, n, 1);
                        break;
		case 2:
                        cin >> v;
                        sgt.set_min(l, r, v, 1, n, 1);
                        break;
		case 3:
                        cout << sgt.query_sum(l, r, 1, n, 1) << '\n';
                        break;
		case 4:
                        cout << sgt.query_max(l, r, 1, n, 1) << '\n';
                        break;
		case 5:
                        cout << sgt.query_hismax(l, r, 1, n, 1) << '\n';
                        break;
		}
	}

        return 0;
}